/*
 * Copyright 2011-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0.
 * See `LICENSE` in the project root for license information.
 */

package me.ijleex.mgmt.framework.util.lotterydraw;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import me.ijleex.mgmt.commons.util.MathUtils;

/**
 * 概率抽奖工具类
 *
 * @author liym
 * @author Li-Shunli
 * @since 2016-08-18 15:13:33 新建
 */
public final class LotteryUtils {

    private static final double ZERO = 0.0D;

    private LotteryUtils() {}

    /**
     * 抽奖
     *
     * <p>probability：[ˌprɑ:bəˈbɪləti]，n. 可能性;几率，概率;或然性</p>
     *
     * @param probabilityList 原始的概率列表，保证顺序与实际物品对应
     * @return 抽中奖品的索引
     */
    public static int lottery(List<Double> probabilityList) {
        if (probabilityList == null || probabilityList.isEmpty()) {
            return -1;
        }

        // 计算概率总和，可以不是1，可以认为这里的概率是一个权重
        double sumPR = ZERO;
        for (double p : probabilityList) {
            sumPR += p;
        }

        if (MathUtils.isNullOrZero(sumPR)) {
            return -1;
        }

        // 计算每个奖品的所占的概率区间
        // 例如，奖品A概率区间 0-0.1，奖品B概率区间 0.1-0.5，奖品C概率区间 0.5-1
        // 每个奖品的中奖率越大，所占的概率区间就越大
        List<Double> intervalPRs = new ArrayList<>(probabilityList.size() + 1);

        // 概率所占比例
        double tmpSumPR = ZERO;
        for (double p : probabilityList) {
            tmpSumPR += p;

            // 构建一个比例区间段组成的集合（避免概率和不为1）
            intervalPRs.add(tmpSumPR / sumPR);
        }

        // 根据区块值来获取抽取到的物品索引

        // 产生一个 0-1 之间的随机数，作为中奖的概率
        // 随机数在哪个概率区间内，则是哪个奖品
        double hitPR = Math.random();
        if (MathUtils.isNullOrZero(hitPR)) {
            hitPR = Math.random();
        }

        // 将中奖的概率加入到概率区间中，排序后，返回的下标则是中奖奖品的下标
        intervalPRs.add(hitPR);
        Collections.sort(intervalPRs);

        return intervalPRs.indexOf(hitPR);
    }

}
